﻿using System;
using System.IO;
using DocumentFormat.OpenXml.Packaging;

#region License
/* Copyright (C) 2009 Tim Coulter
 * 
 * This file is part of ExtremeML.
 * 
 * ExtremeML is free software: you can redistribute
 * it and/or modify it under the terms of the GNU General Public
 * License, as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 * 
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
 * the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see http://www.gnu.org/licenses/.
*/
#endregion

namespace ExtremeML.Core
{
	/// <summary>
	/// Serves as the base class for classes that wrap instances of <see cref="OpenXmlPackage"/>.
	/// </summary>
	/// <typeparam name="TWrapped">A type that derives from <see cref="OpenXmlPackage"/>.</typeparam>
	public abstract class PackageWrapper<TWrapped> : WrapperBase<TWrapped>, IDisposable
		where TWrapped : OpenXmlPackage
	{
		private readonly Stream _source;
		private readonly Stream _target;
	
		/// <summary>
		/// Initializes a new instance of the <see cref="PackageWrapper{TWrapped}"/> class.
		/// </summary>
		/// <param name="wrapped">An <see cref="OpenXmlPackage"/> from which to populate this instance.</param>
		/// <param name="source">The <see cref="Stream"/> from which the wrapped package was populated.</param>
		/// <param name="target">The <see cref="Stream"/> to which the result will be written.</param>
		protected PackageWrapper(
			TWrapped wrapped,
			Stream source,
			Stream target)
			: base(wrapped)
		{
			_source = source;
			_target = target;
		}

		/// <summary>
		/// Flushes and saves the content, closes the package, and releases all resources. 
		/// </summary>
		public void Dispose()
		{
			Deactivate();
			Recompose();
			Wrapped.Dispose();

			if (_source != null && _target != null && _source.CanSeek)
			{
				var buffer = new byte[(int)_source.Length];

				_source.Position = 0;
				_source.Read(buffer, 0, buffer.Length);

				_target.Write(buffer, 0, buffer.Length);
			}

			if (_source != null)
			{
				// The source stream may have been passed by the client application or created
				// internally to open a package specified by its path, so is always disposed.
				// In keeping with the behavior of the SDK, the target stream is not disposed,
				// as it may be subsequently required by the client application.
				_source.Dispose();
			}
		}

		/// <summary>
		/// Returns the wrapped content object as an <see cref="OpenXmlPartContainer"/>.
		/// </summary>
		public OpenXmlPartContainer GetPartContainer()
		{
			return Wrapped;
		}

		/// <summary>
		/// When overridden in a derived class, re-creates the wrapped package from its representative objects.
		/// </summary>
		protected abstract void Recompose();
	}
}
